using System;
using System.Security;
using System.Threading;

namespace InfiniTec.Threading
{
	public sealed class DispatcherCookie : IEquatable<DispatcherCookie>, IComparable<DispatcherCookie>, IComparable
	{
		private readonly DateTime _CallbackTime;
		private readonly WaitCallback _Callback;
		private readonly object _State;
		private readonly SecurityContext _SecurityContext;

		public bool Equals(DispatcherCookie dispatcherCookie)
		{
			if (dispatcherCookie == null) return false;
			if (!Equals(_CallbackTime, dispatcherCookie._CallbackTime)) return false;
			if (!Equals(_Callback, dispatcherCookie._Callback)) return false;
			if (!Equals(_State, dispatcherCookie._State)) return false;
			return true;
		}

		public override bool Equals(object obj)
		{
			if (ReferenceEquals(this, obj)) return true;
			return Equals(obj as DispatcherCookie);
		}

		public override int GetHashCode()
		{
			int result = _CallbackTime.GetHashCode();
			result = 29 * result + _Callback.GetHashCode();
			result = 29 * result + (_State != null ? _State.GetHashCode() : 0);
			return result;
		}

		public DispatcherCookie(DateTime callbackTime, WaitCallback callback, object state)
		{
			_Callback = callback;
			_State = state;
			_CallbackTime = callbackTime;
			_SecurityContext = SecurityContext.Capture();
		}

		internal DateTime CallbackTime
		{
			get { return _CallbackTime; }
		}

		internal WaitCallback Callback
		{
			get { return _Callback; }
		}

		public object State
		{
			get { return _State; }
		}


		public int CompareTo(DispatcherCookie other)
		{
			return other == null ? 1 : CallbackTime.CompareTo(other.CallbackTime);
		}

		public int CompareTo(object obj)
		{
			return CompareTo(obj as DispatcherCookie);
		}

		public void ExecuteCallbackAsync()
		{
			ThreadPool.UnsafeQueueUserWorkItem(state => SecurityContext.Run(_SecurityContext, contextState => Callback(contextState), state), _State);
		}
	}
}